//==========================================================================================
//
//		System.Windows.Forms.AxHost
//		Copyright (c) 2005, OpenNETCF.org
//
//		This library is free software; you can redistribute it and/or modify it under 
//		the terms of the OpenNETCF.org Shared Source License.
//
//		This library is distributed in the hope that it will be useful, but 
//		WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
//		FITNESS FOR A PARTICULAR PURPOSE. See the OpenNETCF.org Shared Source License 
//		for more details.
//
//		You should have received a copy of the OpenNETCF.org Shared Source License 
//		along with this library; if not, email licensing@opennetcf.org to request a copy.
//
//		If you wish to contact the OpenNETCF Advisory Board to discuss licensing, please 
//		email licensing@opennetcf.org.
//
//		For general enquiries, email enquiries@opennetcf.org or visit our website at:
//		http://www.opennetcf.org
//
//==========================================================================================

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Windows.Forms;
using Microsoft.WindowsCE.Forms;
using System.Collections.Generic;
using System.Text;

namespace System.Windows.Forms
{
    public partial class AxHost : Control
    {
        class OleSite :
            IOleClientSite,
            IOleControlSite,
            IOleInPlaceSite,
            IPropertyNotifySink
        {
            private AxHost host;
            private ConnectionPointCookie connectionPoint;

            public OleSite(AxHost _host)
            {
                host = _host;
            }

            public AxHost GetAxHost() { return host; }

            internal void StopEvents()
            {
                if (this.connectionPoint != null)
                {
                    this.connectionPoint.Disconnect();
                    this.connectionPoint = null;
                }
            }
 


            #region IOleClientSite Members

            int IOleClientSite.SaveObject()
            {
                return 0;
            }

            int IOleClientSite.GetMoniker(int dwAssign, int dwWhichMoniker, out object moniker)
            {
                moniker = null;
                return E_NOTIMPL;
            }
            int IOleClientSite.GetContainer(out IOleContainer container)
            {
                container = this.host.GetParentContainer();
                return S_OK;
            }

            int IOleClientSite.ShowObject()
            {
                if (!this.host.GetAxState(AxHost.fOwnWindow))
                {
                    IntPtr hWndInplace;
                    if (this.host.GetAxState(AxHost.fFakingWindow))
                    {
                        this.host.DestroyFakeWindow();
                        this.host.TransitionDownTo(1);
                        this.host.TransitionUpTo(4);
                    }
                    if (this.host.GetOcState() < 4)
                    {
                        return 0;
                    }
                    if (Succeeded(this.host.GetInPlaceObject().GetWindow(out hWndInplace)))
                    {
                        if (this.host.GetHandleNoCreate() != hWndInplace)
                        {
                            //this.host.DetachWindow();
                            if (hWndInplace != IntPtr.Zero)
                            {
                                //this.host.AttachWindow(hWndInplace);
                            }
                        }
                    }
                    //else if (this.host.GetInPlaceObject() is IOleInPlaceObjectWindowless)
                    //{
                    //    throw new InvalidOperationException("AXWindowlessControl");
                    //}
                }
                return 0;
            }

            int IOleClientSite.OnShowWindow(int fShow)
            {
                return S_OK;
            }

            int IOleClientSite.RequestNewObjectLayout()
            {
                return E_NOTIMPL;
            }

            #endregion

            #region IOleControlSite Members

            int IOleControlSite.OnControlInfoChanged()
            {
                return S_OK;
            }

            int IOleControlSite.LockInPlaceActive(int fLock)
            {
                return E_NOTIMPL;
            }

            int IOleControlSite.GetExtendedControl(out object ppDisp)
            {
                ppDisp = this.host.GetParentContainer().GetProxyForControl(this.host);
                if (ppDisp == null)
                {
                    return E_NOTIMPL;
                }
                return S_OK;
            }

            // Do nothing. We do not support anything but MM_TEXT
            int IOleControlSite.TransformCoords(POINTL pPtlHimetric, tagPOINTF pPtfContainer, int dwFlags)
            {
                return S_OK;
            }

            //TODO: Add proper accelerator handling
            int IOleControlSite.TranslateAccelerator(ref MSG pMsg, int grfModifiers)
            {
                Message msg = new Message();
                int ret;
                //this.host.SetAxState(AxHost.siteProcessedInputKey, true);
                msg = new Message();
                msg.Msg = pMsg.message;
                msg.WParam = pMsg.wParam;
                msg.LParam = pMsg.lParam;
                msg.HWnd = pMsg.hwnd;
                try
                {
                    ret = this.host.PreProcessMessage(ref msg) ? 0 : 1;
                }
                finally
                {
                    //this.host.SetAxState(AxHost.siteProcessedInputKey, false);
                }
                return ret;

            }

            int IOleControlSite.OnFocus(int fGotFocus)
            {
                return S_OK;
            }

            // Property pages are not supported
            int IOleControlSite.ShowPropertyFrame()
            {
                return E_NOTIMPL;
            }

            #endregion

            #region IOleInPlaceSite Members

            IntPtr IOleInPlaceSite.GetWindow()
            {
                IntPtr hWnd;
                try
                {
                    Control hostParent = this.host.ParentInternal;
                    hWnd = (hostParent != null) ? hostParent.Handle : host.Handle; //IntPtr.Zero;
                }
                catch (Exception ex)
                {
                    throw ex;
                }
                catch
                {
                    throw;
                }
                return hWnd;

            }

            int IOleInPlaceSite.ContextSensitiveHelp(int fEnterMode)
            {
                return E_NOTIMPL;
            }

            int IOleInPlaceSite.CanInPlaceActivate()
            {
                return S_OK;
            }

            int IOleInPlaceSite.OnInPlaceActivate()
            {
                
                this.host.SetAxState(AxHost.ownDisposing, false);
                this.host.SetAxState(AxHost.rejectSelection, false);
                this.host.SetOcState(4);
                
                return S_OK;
            }

            int IOleInPlaceSite.OnUIActivate()
            {
                
                this.host.SetOcState(8);
                this.host.GetParentContainer().OnUIActivate(this.host);
                
                return 0;
            }

            int IOleInPlaceSite.GetWindowContext(out IOleInPlaceFrame ppFrame, out IOleInPlaceUIWindow ppDoc, COMRECT lprcPosRect, COMRECT lprcClipRect, tagOIFI lpFrameInfo)
            {
                ppDoc = null;
                ppFrame = this.host.GetParentContainer();
                AxHost.FillInRect(lprcPosRect, this.host.Bounds);
                this.host.GetClipRect(lprcClipRect);
                if (lpFrameInfo != null)
                {
                    lpFrameInfo.cb = Marshal.SizeOf(typeof(tagOIFI));
                    lpFrameInfo.fMDIApp = false;
                    lpFrameInfo.hAccel = IntPtr.Zero;
                    lpFrameInfo.cAccelEntries = 0;
                    lpFrameInfo.hwndFrame = this.host.Handle;
                }
                return 0;
            }

            int IOleInPlaceSite.Scroll(tagSIZE scrollExtant)
            {
                return S_FALSE;
            }

            int IOleInPlaceSite.OnUIDeactivate(int fUndoable)
            {
                
                host.GetParentContainer().OnUIDeactivate(host);
                if (host.GetOcState() > 4)
                {
                    host.SetOcState(4);
                }
                
                return S_OK;
            }

            int IOleInPlaceSite.OnInPlaceDeactivate()
            {
                
                if (this.host.GetOcState() == 8)
                {
                    ((IOleInPlaceSite)this).OnUIDeactivate(0);
                }
                this.host.GetParentContainer().OnInPlaceDeactivate(this.host);
                //this.host.DetachWindow();
                this.host.SetOcState(2);
                
                return S_OK;
            }

            int IOleInPlaceSite.DiscardUndoState()
            {
                return S_OK;
            }

            int IOleInPlaceSite.DeactivateAndUndo()
            {
                return this.host.GetInPlaceObject().UIDeactivate();
                //return S_OK;
            }

            int IOleInPlaceSite.OnPosRectChange(COMRECT lprcPosRect)
            {
                
                bool flag1 = true;
                if (AxHost.windowsMediaPlayer_Clsid.Equals(this.host.clsid))
                {
                    flag1 = this.host.GetAxState(AxHost.handlePosRectChanged);
                }
                if (flag1)
                {
                    COMRECT rect = new COMRECT();
                    this.host.GetClipRect( rect);
                    this.host.GetInPlaceObject().SetObjectRects(lprcPosRect, rect);
                    //this.host.MakeDirty();
                }
                
                return S_OK;
            }

            #endregion

            #region IPropertyNotifySink Members

            void IPropertyNotifySink.OnChanged(int dispID)
            {
            }

            int IPropertyNotifySink.OnRequestEdit(int dispID)
            {
                return S_OK;
            }

            #endregion

            public bool Succeeded(int hr)
            {
                return (hr & 0x80000000) == 0;
            }

            public bool Failed(int hr)
            {
                return (hr & 0x80000000) != 0;
            }

            internal void OnOcxCreate()
            {
                this.StartEvents();
            }

            internal void StartEvents()
            {
                if (this.connectionPoint == null)
                {
                    object ocx = this.host.GetOcx();
                    try
                    {
                        connectionPoint = new ConnectionPointCookie(ocx, this, typeof(IPropertyNotifySink));
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine(ex.Message);
                    }
                }
            }
 

        }

        /// <summary>
        /// Wraps Advise/Unadvise functionality for connection point
        /// </summary>
        public class ConnectionPointCookie
        {
            #region Methods

            /// <summary>
            /// Constructs a new ConnectionPointCookie and connects sink to source using 
            /// specified event interface
            /// </summary>
            /// <param name="source">Event source</param>
            /// <param name="sink">Event sink</param>
            /// <param name="eventInterface">Event interface</param>
            public ConnectionPointCookie(object source, object sink, Type eventInterface)
            {
                if (source is IConnectionPointContainer)
                {
                    IConnectionPointContainer cont = (IConnectionPointContainer)source;
                    try
                    {
                        Guid guidType = TypeHelper.GetTypeGuid(eventInterface);
                        cont.FindConnectionPoint(ref guidType, out this.connectionPoint);
                    }
                    catch (Exception ex)
                    {
                        System.Diagnostics.Debug.WriteLine(ex);
                        this.connectionPoint = null;
                    }
                    
                    if (this.connectionPoint == null)
                        throw new ArgumentException("AxHost: ConnectionPointContainer does not have CP interface " + eventInterface.Name);
                    else if ((sink == null) || !eventInterface.IsInstanceOfType(sink))
                        throw new InvalidCastException("AxHost: Sink is null or does not implement CP interface " + eventInterface.Name);
                    else
                    {
                        try
                        {
                            connectionPoint.Advise(sink, out cookie);
                        }
                        catch
                        {
                            cookie = 0;
                            Marshal.ReleaseComObject(this.connectionPoint);
                            connectionPoint = null;
                            throw new InvalidOperationException("AxHost: Advise failed");
                        }
                    }
                }
                else
                {
                    throw new InvalidCastException(("AxHost: Object does not implement IConnectionPointContainer"));
                }
                if ((this.connectionPoint == null) || (this.cookie == 0))
                {
                    if (this.connectionPoint != null)
                    {
                        Marshal.ReleaseComObject(this.connectionPoint);
                    }
                    throw new InvalidOperationException("AxHost: Attach to connection point failed");
                }
            }

            /// <summary>
            /// Removes Connection Point connection
            /// </summary>
            public void Disconnect()
            {
                if ((this.connectionPoint != null) && (this.cookie != 0))
                {
                    try
                    {
                        this.connectionPoint.Unadvise(this.cookie);
                    }
                    catch
                    {
                    }
                    finally
                    {
                        this.cookie = 0;
                    }
                    try
                    {
                        Marshal.ReleaseComObject(this.connectionPoint);
                    }
                    catch
                    {
                        return;
                    }
                    finally
                    {
                        this.connectionPoint = null;
                    }
                }
            }


            /// <summary>
            /// Cleanup
            /// </summary>
            ~ConnectionPointCookie()
            {
                this.Disconnect();
            }
            #endregion

            // Fields
            private IConnectionPoint connectionPoint;
            private int cookie;
        }
 


        public const int E_NOTIMPL = -2147467263;
        public const int E_INVALIDARG = -2147024809;
        public const int S_OK = 0;
        public const int S_FALSE = 1;
        public const int E_FAIL = -2147467259;
    }

}
